package cn.redragon.soa.config.web;

import static cn.redragon.soa.common.core.constant.AuthConstant.API_KEY_HEADER;
import static cn.redragon.soa.common.core.constant.AuthConstant.AUTH_HEADER;
import static cn.redragon.soa.common.core.constant.AuthConstant.TOKEN_HEADER;
import static cn.redragon.soa.common.core.constant.AuthConstant.X_API_KEY_HEADER;
import static feign.Logger.Level.HEADERS;

import cn.redragon.soa.common.core.util.JsonUtil;
import com.google.common.collect.Maps;
import feign.Logger.JavaLogger;
import feign.Request;
import feign.Response;
import feign.Util;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;

@Slf4j
public class CommonFeignLogger extends JavaLogger {

    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {

        if (logLevel.ordinal() <= HEADERS.ordinal()) {
            super.logRequest(configKey, logLevel, request);
        } else {
            //override for log level >= FULL
            Iterator var4 = request.headers().keySet().iterator();

            String headerText;
            Map<String, String> headerMap = Maps.newHashMap();
            while (var4.hasNext()) {
                headerText = (String) var4.next();
                Iterator var6 = Util.valuesOrEmpty(request.headers(), headerText).iterator();

                while (var6.hasNext()) {
                    String value = (String) var6.next();
                    if (this.getMaskedHeaders().stream().anyMatch(headerText::equalsIgnoreCase)) {
                        value = "masked";
                    }
                    headerMap.put(headerText, value);
                }
            }

            String bodyText = StringUtils.EMPTY;
            int bodyLength = 0;
            if (request.body() != null) {
                bodyLength = request.length();
                bodyText = request.charset() != null ? new String(request.body(), request.charset()) : "Binary data";
            }

            log(configKey, "---> %s %s HTTP/1.1 (%s-byte body) headers=[%s], payload=[%s]", request.httpMethod().name(), request.url(), bodyLength,
                JsonUtil.objectToJsonStr(headerMap), bodyText);
        }
    }

    @Override
    protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime)
        throws IOException {
        if (logLevel.ordinal() <= HEADERS.ordinal()) {
            super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
        } else {
            //override for log level >= FULL
            Request request = response.request();
            String reason = response.reason() != null ? " " + response.reason() : "";
            int status = response.status();
            Map<String, String> headerMap = Maps.newHashMap();
            Iterator var8 = response.headers().keySet().iterator();

            while (var8.hasNext()) {
                String field = (String) var8.next();
                Iterator var10 = Util.valuesOrEmpty(response.headers(), field).iterator();

                while (var10.hasNext()) {
                    String value = (String) var10.next();
                    headerMap.put(field, value);
                }
            }

            int bodyLength = 0;
            String bodyText = StringUtils.EMPTY;
            if (response.body() != null && status != HttpStatus.SC_NO_CONTENT && status != HttpStatus.SC_RESET_CONTENT) {
                byte[] bodyData = Util.toByteArray(response.body().asInputStream());
                bodyLength = bodyData.length;
                if (bodyLength > 0) {
                    bodyText = Util.decodeOrDefault(bodyData, Util.UTF_8, "Binary data");
                }
                log(configKey, "<--- %s %s HTTP/1.1 %s%s (%sms) (%s-byte body) headers=[%s], payload=[%s]", request.httpMethod().name(), request.url(), status,
                    reason, elapsedTime, bodyLength, JsonUtil.objectToJsonStr(headerMap), bodyText);
                return response.toBuilder().body(bodyData).build();
            }
            this.log(configKey, "<--- %s %s HTTP/1.1 %s%s (%sms) (%s-byte body) headers=[%s]", request.httpMethod().name(), request.url(), status,
                     reason, elapsedTime, Integer.valueOf(bodyLength), JsonUtil.objectToJsonStr(headerMap));
        }
        return response;
    }

    @Override
    protected void log(String configKey, String format, Object... args) {
        log.debug(format(configKey, format, args));
    }

    protected String format(String configKey, String format, Object... args) {
        return String.format(methodTag(configKey) + format, args);
    }

    private List<String> getMaskedHeaders() {
        return List.of(AUTH_HEADER, TOKEN_HEADER, X_API_KEY_HEADER, API_KEY_HEADER);
    }
}